package com.econ.powercloud.ems.service.biz;

import com.alibaba.fastjson.JSON;
import com.econ.powercloud.clickhouse.dao.AnalogDataDAO;
import com.econ.powercloud.clickhouse.dao.PlanDataDAO;
import com.econ.powercloud.clickhouse.dao.StatusDataDAO;
import com.econ.powercloud.clickhouse.entity.AnalogData;
import com.econ.powercloud.clickhouse.entity.PlanData;
import com.econ.powercloud.clickhouse.entity.StatusData;
import com.econ.powercloud.common.base.facade.enums.StatusType;
import com.econ.powercloud.common.base.facade.exception.CommonRuntimeException;
import com.econ.powercloud.common.base.facade.pojo.MsgResult;
import com.econ.powercloud.common.base.facade.pojo.PageResult;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.*;
import com.econ.powercloud.ems.common.pojo.IotSyncMsgDTO;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.dal.entity.ext.IotEdgePlatformSyncMsg;
import com.econ.powercloud.ems.dal.entity.ext.IotEdgePlatformSyncMsgDetail;
import com.econ.powercloud.ems.dal.mapper.ExtIotNodeMapper;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.pojo.requestVO.*;
import com.econ.powercloud.ems.rpc.IFeignPowerNodeConsoleClient;
import com.econ.powercloud.ems.service.common.QueryCalDataCommonService;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.dao.*;
import com.econ.powercloud.ems.util.NetUtils;
import com.econ.powercloud.ems.util.PageUtil;
import com.econ.powercloud.ems.util.TimeUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.validation.constraints.Max;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description :
 * @Date : 2022/10/20 13:52
 * @Modified by : zjf
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EmsAdvancedStrategyService {

    private final EmsConstantConfigDAO emsConstantConfigDAO;
    private final EmsDeviceDAO emsDeviceDAO;
    private final EmsModuleConfigDAO emsModuleConfigDAO;
    private final QueryFlashDataCommonService queryFlashDataCommonService;
    private final QueryCalDataCommonService queryCalDataCommonService;
    private final AnalogDataDAO analogDataDAO;
    private final StatusDataDAO statusDataDAO;
    private final PlanDataDAO planDataDAO;
    private final EmsStrategyConfigDAO emsStrategyConfigDAO;
    private final IotMqttSyncMsgDAO iotMqttSyncMsgDAO;
    private final IotMqttSyncMsgDetailDAO iotMqttSyncMsgDetailDAO;
    private final IFeignPowerNodeConsoleClient iFeignPowerNodeConsoleClient;
    private final EmsDeviceMonitorConfigDAO emsDeviceMonitorConfigDAO;
    private final ExtIotViceCalculationDAO extIotViceCalculationDAO;
    private final EmsEnergyEquipmentDAO emsEnergyEquipmentDAO;
    private final IotProductEventScriptDAO productEventScriptDAO;
    private final IotDeviceYkYtDitDAO iotDeviceYkYtDitDAO;
    private final ExtIotNodeDAO extIotNodeDAO;

    @Transactional(rollbackFor = Exception.class)
    public void saveConfigDit(Integer module, List<ModuleConfigRequestVO> requestVOList){
        List<EmsModuleConfig> insertList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(requestVOList)){
            List<String> deviceCodeList = requestVOList.stream().map(ModuleConfigRequestVO::getDeviceCode).collect(Collectors.toList());
            Map<String,EmsDevice> emsDeviceMap = emsDeviceDAO.selectByDeviceCodes(deviceCodeList).stream().collect(Collectors.toMap(EmsDevice::getDeviceCode,d->d,(p1,p2)->p1));
            requestVOList.stream().forEach(d->{
                insertList.add(EmsModuleConfig.builder()
                        .category(ModulePositionEnum.fromCode(module).getCategoryEnum().getCode())
                        .module(module).deviceCode(d.getDeviceCode())
                        .ditType(d.getDitType()).pid(emsDeviceMap.get(d.getDeviceCode()).getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                        .initDeviceCode(emsDeviceMap.get(d.getDeviceCode()).getInitDeviceCode())
                        .pidName(d.getDitName()).pidAliasName(d.getAliasName()).gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis())
                        .build());
            });
        }
        emsModuleConfigDAO.deleteByModule(module);
        if(CollectionUtils.isNotEmpty(requestVOList)){
            emsModuleConfigDAO.saveBatch(insertList);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveConstantSet(Integer module,List<ConstantSetRequestVO> requestVOList){
        List<EmsConstantConfig> hisConfigList = emsConstantConfigDAO.getBaseMapper().selectHisByModule(module);
        //key：deviceCode+"."+ditType+"."+dit, value: setVal
        Map<String,String> hisConfigMap = Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(hisConfigList)){
            hisConfigMap.putAll(hisConfigList.stream().collect(
                    Collectors.groupingBy(d->d.getDeviceCode() + "." + d.getDitType() + "." + d.getDit(), Collectors.collectingAndThen(Collectors.toList(),
                            value->value.stream().sorted(Comparator.comparing(EmsConstantConfig::getGmtCreate).reversed()).collect(Collectors.toList()).get(0).getSetVal()))));
        }
        List<EmsConstantConfig> insertList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(requestVOList)){
            requestVOList.stream().forEach(d->{
                String setVal = hisConfigMap.get(d.getDeviceCode() + "." + d.getDitType() + "." + d.getDit());
                insertList.add(EmsConstantConfig.builder()
                        .category(ModulePositionEnum.fromCode(module).getCategoryEnum().getCode())
                        .module(module).name(d.getDitName()).setVal(setVal)
                        .deviceCode(d.getDeviceCode()).ditType(d.getDitType()).dit(d.getDit()).ditName(d.getDitName())
                        .feedBackDitType(d.getFeedBackDitType()).feedBackDit(d.getFeedBackDit()).feedBackDitName(d.getFeedBackDitName())
                        .actualDitType(d.getActualDitType()).actualDit(d.getActualDit()).actualDitName(d.getActualDitName())
                        .gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis())
                        .build());
            });
        }
        emsConstantConfigDAO.deleteByModule(module);
        if(CollectionUtils.isNotEmpty(insertList)){
            emsConstantConfigDAO.saveBatch(insertList);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void modifyConstantSet(Integer id, ConstantSetEdit edit){
        EmsConstantConfig config = emsConstantConfigDAO.getById(id);
        Assert.notNull(config,"该常量不存在!");
        Assert.notNull(config.getDit(),"未配置设定点号");
        if(!DitTypeEnum.isYkYt(config.getDitType())){
            throw new CommonRuntimeException(StatusType.FAIL,"非遥控遥调点号无法设定下发值！");
        }
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(config.getDeviceCode());
        Assert.notNull(emsDevice,"设定下发值的设备不存在！");
        //下发遥控遥调点号
        if(Objects.equals(DitTypeEnum.YK.getCode(),config.getDitType())){
            //下发遥控
            MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yk(NetUtils.getClientIp(),null,emsDevice.getInitDeviceCode(), config.getDit(), edit.getSetVal().intValue(),false);
            if(StatusType.OK.getCode() != result.getStatus()){
                throw new CommonRuntimeException(StatusType.FAIL, result.getStatusText());
            }
        }else {
            //下发遥调
            MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yt(NetUtils.getClientIp(),null,emsDevice.getInitDeviceCode(),config.getDit(),edit.getSetVal(),false);
            if(StatusType.OK.getCode() != result.getStatus()){
                throw new CommonRuntimeException(StatusType.FAIL, result.getStatusText());
            }
        }
        config.setSetVal(edit.getSetVal()+"");
        config.setGmtModify(System.currentTimeMillis());
        emsConstantConfigDAO.updateById(config);
    }

    /**
     * 获取点号配置信息
     * @param module 模块位置
     * @return
     */
    public List<ModuleConfigVO> getConfigDit(Integer module) {
        List<ModuleConfigVO> moduleConfigVOS = Lists.newArrayList();
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModule(module);
        if (CollectionUtils.isNotEmpty(emsModuleConfigs)) {
            List<EmsDevice> emsDevices = emsDeviceDAO.selectByDeviceCodes(emsModuleConfigs.stream().map(EmsModuleConfig::getDeviceCode).collect(Collectors.toList()));
            Map<String, String> deviceCodeNameMap = emsDevices.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, EmsDevice::getDeviceName, (e1, e2) -> e2));
            emsModuleConfigs.stream().forEach(m -> {
                ModuleConfigVO vo = ModuleConfigVO.builder()
                        .id(m.getId())
                        .deviceCode(m.getDeviceCode())
                        .deviceName(deviceCodeNameMap.get(m.getDeviceCode()))
                        .ditType(m.getDitType()).ditTypeName(DitTypeEnum.getDescFromCode(m.getDitType()))
                        .dit(m.getPid().replace(m.getInitDeviceCode() + SysConstant.SPOT, ""))
                        .ditName(m.getPidName())
                        .aliasName(m.getPidAliasName())
                        .build();
                moduleConfigVOS.add(vo);
            });
        }
        return moduleConfigVOS;
    }

    /**
     * 获取常量配置信息
     * @param module 模块位置
     * @return
     */
    public List<ConstantConfigVO> getConfigConstant(Integer module) {
        List<ConstantConfigVO> voList = Lists.newArrayList();
        List<EmsConstantConfig> constantConfigs = emsConstantConfigDAO.selectByModule(module);
        if (CollectionUtils.isNotEmpty(constantConfigs)) {
            List<EmsDevice> emsDevices = emsDeviceDAO.selectByDeviceCodes(constantConfigs.stream().map(EmsConstantConfig::getDeviceCode).collect(Collectors.toList()));
            Map<String, EmsDevice> deviceMap = emsDevices.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, d->d, (e1, e2) -> e2));
            //获取遥调上下限数据
            List<IotDeviceYkYtDit> iotDeviceYkYtDits = iotDeviceYkYtDitDAO.getByDeviceCode(emsDevices.stream().map(EmsDevice::getInitDeviceCode).collect(Collectors.toList()));
            Map<String,IotDeviceYkYtDit> ykYtDitMap = iotDeviceYkYtDits.stream().collect(Collectors.toMap(d->d.getDeviceCode()+SysConstant.SPOT+d.getDit(),d->d));
            //组装查看反馈点号,实际点号的数据信息
            List<QueryDataVO> queryList = Lists.newArrayList();
            List<QueryDataVO> calQueryList = Lists.newArrayList();
            this.createConstantConfigQueryData(deviceMap,constantConfigs,queryList,calQueryList);
            //获取反馈点号,实际点号的实时数据
            List<FlashDataVO> flashDataVOS = queryFlashDataCommonService.getFlashData(queryList);
            Map<String, String> flashDataValueMap = flashDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
            List<FlashDataVO> calFlashVOs = queryCalDataCommonService.getCalData(calQueryList);
            Map<String, String> calFlashDataValueMap = calFlashVOs.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
            voList = JacksonUtil.convertToList(constantConfigs, ConstantConfigVO.class);
            voList.stream().forEach(v -> {
                EmsDevice emsDevice = deviceMap.get(v.getDeviceCode());
                if(v.getFeedBackDit() != null){
                    if(DitTypeEnum.isFlashData(v.getFeedBackDitType())){
                        v.setFeedBackDitValue(flashDataValueMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + v.getFeedBackDit()));
                    }else if(DitTypeEnum.isCalData(v.getFeedBackDitType())){
                        v.setFeedBackDitValue(calFlashDataValueMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + v.getFeedBackDit()));
                    }
                }
                if(v.getActualDit() != null){
                    if(DitTypeEnum.isFlashData(v.getActualDitType())){
                        v.setActualDitValue(flashDataValueMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + v.getActualDit()));
                    }else if(DitTypeEnum.isCalData(v.getActualDitType())){
                        v.setActualDitValue(calFlashDataValueMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + v.getActualDit()));
                    }
                }
                String key = emsDevice.getInitDeviceCode()+SysConstant.SPOT+v.getDit();
                IotDeviceYkYtDit ykytDit;
                if ((ykytDit = ykYtDitMap.get(key))!=null){
                    v.setRangeStart(ykytDit.getRangeStart());
                    v.setRangeEnd(ykytDit.getRangeEnd());
                }
                v.setDeviceName(emsDevice==null?null:emsDevice.getDeviceName());
                v.setDitTypeName(DitTypeEnum.getDescFromCode(v.getDitType()));
                v.setFeedBackDitTypeName(v.getFeedBackDitType() == null?null : DitTypeEnum.getDescFromCode(v.getFeedBackDitType()));
                v.setActualDitTypeName(v.getActualDitType() == null?null : DitTypeEnum.getDescFromCode(v.getActualDitType()));
            });
        }
        return voList;
    }

    public List<FlashVO> getFlashDataByModule(Integer module){
        List<EmsModuleConfig> configList = emsModuleConfigDAO.selectListByModule(module);
        if(CollectionUtils.isEmpty(configList)){
            return Collections.emptyList();
        }
        //查询实时数据
        List<QueryDataVO> queryList = Lists.newArrayList();
        List<QueryDataVO> calQueryList = Lists.newArrayList();
        configList.stream().forEach(d->{
            QueryDataVO queryDataVO = QueryDataVO.builder().deviceCode(d.getDeviceCode())
                    .pid(d.getPid()).initDeviceCode(d.getInitDeviceCode())
                    .dit(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT,""))
                    .build();
            if(Objects.equals(d.getDitType(), DitTypeEnum.YC.getCode()) || Objects.equals(d.getDitType(), DitTypeEnum.YX.getCode())){
                queryList.add(queryDataVO);
            }else if(Objects.equals(d.getDitType(), DitTypeEnum.CAL_YC.getCode()) || Objects.equals(d.getDitType(), DitTypeEnum.CAL_YX.getCode())){
                calQueryList.add(queryDataVO);
            }
        });
        List<FlashDataVO> flashDataVOS = queryFlashDataCommonService.getFlashData(queryList);
        Map<String, FlashDataVO> flashDataMap = flashDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p));
        List<FlashDataVO> calFlashVOs = queryCalDataCommonService.getCalData(calQueryList);
        Map<String, FlashDataVO> calFlashDataMap = calFlashVOs.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p));
        List<FlashVO> result = Lists.newArrayList();
        configList.stream().forEach(d->{
            FlashDataVO flashDataVO = null;
            if(Objects.equals(d.getDitType(), DitTypeEnum.YC.getCode()) || Objects.equals(d.getDitType(), DitTypeEnum.YX.getCode())){
                flashDataVO = flashDataMap.get(d.getPid());
            }else if(Objects.equals(d.getDitType(), DitTypeEnum.CAL_YC.getCode()) || Objects.equals(d.getDitType(), DitTypeEnum.CAL_YX.getCode())){
                flashDataVO = calFlashDataMap.get(d.getPid());
            }
            result.add(FlashVO.builder()
                    .pid(d.getPid()).initDeviceCode(d.getInitDeviceCode())
                    .ditType(d.getDitType())
                    .name(d.getPidName()).value(flashDataVO == null?null : flashDataVO.getVal())
                    .unit(flashDataVO == null?null : flashDataVO.getUnit())
                    .build());
        });
        return result;
    }

    /**
     * 获取历史数据
     * @param module 模块位置
     * @param isAsc true:升序，false:降序
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    public List<HisChartDataVO> getHisDataByModule(Integer module, Boolean isAsc, Long startTime, Long endTime) {
        List<HisChartDataVO> resultList = Lists.newArrayList();
        //获取该位置所配置的点号
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModule(module);
        List<String> ycPids = emsModuleConfigs.stream().filter(e-> e.getDitType().equals(DitTypeEnum.YC.getCode()) || e.getDitType().equals(DitTypeEnum.CAL_YC.getCode())).map(EmsModuleConfig::getPid).collect(Collectors.toList());
        List<String> yxPids = emsModuleConfigs.stream().filter(e-> e.getDitType().equals(DitTypeEnum.YX.getCode()) || e.getDitType().equals(DitTypeEnum.CAL_YX.getCode())).map(EmsModuleConfig::getPid).collect(Collectors.toList());
        List<String> jhPids = emsModuleConfigs.stream().filter(e-> e.getDitType().equals(DitTypeEnum.JH.getCode())).map(EmsModuleConfig::getPid).collect(Collectors.toList());
        //不同类别分别查询数据
        Map<String, List<AnalogData>> ycDataMap= Maps.newHashMap();
        Map<String, List<StatusData>> yxDataMap= Maps.newHashMap();
        Map<String, List<PlanData>> jhDataMap= Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(ycPids)){
            ycDataMap = analogDataDAO.selectByPidsAndTime(ycPids,isAsc, startTime, endTime)
                    .stream().collect(Collectors.groupingBy(d->d.getPid(), LinkedHashMap::new,Collectors.toList()));
        }
        if(CollectionUtils.isNotEmpty(yxPids)){
            yxDataMap = statusDataDAO.selectByPidsAndTime(yxPids,isAsc, startTime, endTime)
                    .stream().collect(Collectors.groupingBy(d->d.getPid(), LinkedHashMap::new,Collectors.toList()));
        }
        if(CollectionUtils.isNotEmpty(jhPids)){
            jhDataMap = planDataDAO.selectByPidsAndTime(jhPids,isAsc, startTime, endTime)
                    .stream().collect(Collectors.groupingBy(d->d.getPid(), LinkedHashMap::new,Collectors.toList()));
        }
        for (EmsModuleConfig config : emsModuleConfigs){
            List<ChartDataVO> chartDataVOList = Lists.newArrayList();
            if (config.getDitType().equals(DitTypeEnum.YC.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YC.getCode())) {
                //遥测或者计算遥测
                List<AnalogData> analogDatas = ycDataMap.get(config.getPid());
                if(CollectionUtils.isNotEmpty(analogDatas)){
                    analogDatas.forEach(a -> {
                        chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                    });
                }
            } else if (config.getDitType().equals(DitTypeEnum.YX.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YX.getCode())) {
                //遥信或者计算遥信
                List<StatusData> statusDatas = yxDataMap.get(config.getPid());
                if(CollectionUtils.isNotEmpty(statusDatas)){
                    statusDatas.forEach(a -> {
                        chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                    });
                }
            }else if(config.getDitType().equals(DitTypeEnum.JH.getCode())){
                //计划
                List<PlanData> planDatas = jhDataMap.get(config.getPid());
                if(CollectionUtils.isNotEmpty(planDatas)){
                    planDatas.forEach(a -> {
                        chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                    });
                }
            }
            HisChartDataVO hisChartDataVO = HisChartDataVO.builder().pidAliasName(config.getPidAliasName())
                    .deviceCode(config.getDeviceCode()).ditType(config.getDitType()).pid(config.getPid())
                    .datas(chartDataVOList.stream().sorted(isAsc ? Comparator.comparing(ChartDataVO::getTime)
                            : Comparator.comparing(ChartDataVO::getTime).reversed()).collect(Collectors.toList())).build();
            resultList.add(hisChartDataVO);
        }
        return resultList;
    }

    /**
     * 如果需要分页的话，只能返回一个数据的分页
     * @param module
     * @param isAsc
     * @param startTime
     * @param endTime
     * @return
     */
    public PageResult<List<ChartDataVO>> getHisDataByModule(Integer module, Boolean isAsc, Long startTime, Long endTime,Integer pageNo,Integer pageSize) {
        //获取该位置所配置的点号
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModule(module);
        if(CollectionUtils.isEmpty(emsModuleConfigs)){
            return PageResult.<List<ChartDataVO>>builder().totalCount(0).pageNo(pageNo).data(Collections.emptyList()).build();
        }
        EmsModuleConfig config = emsModuleConfigs.get(0);
        List<ChartDataVO> chartDataVOList = Lists.newArrayList();
        if (config.getDitType().equals(DitTypeEnum.YC.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YC.getCode())) {
            //遥测或者计算遥测
            List<AnalogData> analogDatas = analogDataDAO.selectByPidAndTime(config.getPid(), isAsc, startTime, endTime);
            if(CollectionUtils.isNotEmpty(analogDatas)){
                analogDatas.forEach(a -> {
                    chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                });
            }
        } else if (config.getDitType().equals(DitTypeEnum.YX.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YX.getCode())) {
            //遥信或者计算遥信
            List<StatusData> statusDatas = statusDataDAO.selectByPidAndTime(config.getPid(), isAsc, startTime, endTime);
            if(CollectionUtils.isNotEmpty(statusDatas)){
                statusDatas.forEach(a -> {
                    chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                });
            }
        }else if(config.getDitType().equals(DitTypeEnum.JH.getCode())){
            //计划
            List<PlanData> planDatas = planDataDAO.selectByPidsAndTime(Lists.newArrayList(config.getPid()),isAsc,startTime,endTime);
            if(CollectionUtils.isNotEmpty(planDatas)){
                planDatas.forEach(a -> {
                    chartDataVOList.add(ChartDataVO.builder().time(a.getT()).val(a.getV()).build());
                });
            }
        }
        if(CollectionUtils.isEmpty(chartDataVOList)){
            return PageResult.<List<ChartDataVO>>builder().totalCount(0).pageNo(pageNo).data(Collections.emptyList()).build();
        }
        return PageResult.<List<ChartDataVO>>builder().totalCount(chartDataVOList.size()).pageNo(pageNo)
                .data(PageUtil.getPageSizeDataForRelations(chartDataVOList,pageNo,pageSize)).build();
    }

    public List<StrategyVO> getAllStrategy() {
        List<EmsStrategyConfig> list = emsStrategyConfigDAO.list();
        List<StrategyVO> result = JacksonUtil.convertToList(list, StrategyVO.class);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public void strategyConfig(List<StrategyConfigRequestVO> strategyConfigRequestVOList) {
        if (CollectionUtils.isEmpty(strategyConfigRequestVOList)){
            return;
        }
        strategyConfigRequestVOList.stream().forEach(d->
                Assert.notNull(DisplayType.fromCode(d.getDisplay()),String.format("不存在的显示类型：",d.getDisplay())));

        List<EmsStrategyConfig> emsStrategyConfigs = emsStrategyConfigDAO.list();
        List<String> existStrategyIdList = emsStrategyConfigs.stream()
                .map(EmsStrategyConfig::getStrategyId).collect(Collectors.toList());
        //检查有不存在的策略
        List<String> nameList = strategyConfigRequestVOList.stream()
                .filter(d -> !existStrategyIdList.contains(d.getStrategyId()))
                .map(StrategyConfigRequestVO::getStrategyName).collect(Collectors.toList());
        Assert.isTrue(CollectionUtils.isEmpty(nameList),"策略："+String.join(",",nameList)+" 不存在！");

        Map<String, Integer> map = strategyConfigRequestVOList.stream().collect(Collectors.
                toMap(StrategyConfigRequestVO::getStrategyId, StrategyConfigRequestVO::getDisplay));
        emsStrategyConfigs.stream().forEach(d->{
            if (map.containsKey(d.getStrategyId())){
                d.setDisplay(map.get(d.getStrategyId()));
            }
        });
        emsStrategyConfigDAO.updateBatchById(emsStrategyConfigs);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveStrategyControl(List<StrategyControlRequestVO> requestVOList) {
        if (CollectionUtils.isEmpty(requestVOList)) {
            return;
        }
        //先删除，后插入,这里需要根据不同的groupId与module来删除
        requestVOList.stream().forEach(d->{
            emsModuleConfigDAO.deleteByModuleAndGroupId(d.getModule(),d.getGroupId());
        });
        //过滤哪些没有进行配置的请求VO类
        List<StrategyControlRequestVO> requestVOS = requestVOList.stream()
                .filter(d -> !StringUtils.isEmpty(d.getDeviceCode())).collect(Collectors.toList());
        List<String> requestDeviceCodeList = requestVOS.stream()
                .map(StrategyControlRequestVO::getDeviceCode).collect(Collectors.toList());
        List<EmsDevice> emsDeviceList = emsDeviceDAO.selectByDeviceCodes(requestDeviceCodeList);
        if (CollectionUtils.isEmpty(emsDeviceList)) {
            return;
        }
        Map<String, EmsDevice> deviceMap = emsDeviceList.stream()
                .collect(Collectors.toMap(EmsDevice::getDeviceCode, d -> d, (d1, d2) -> d2));
        List<EmsModuleConfig> insertList = Lists.newArrayList();
        for (StrategyControlRequestVO requestVO : requestVOS) {
            //新插入的数据
            insertList.addAll(strategyToModuleConfigList(requestVO, deviceMap));
        }
        if (CollectionUtils.isNotEmpty(insertList)) {
            emsModuleConfigDAO.saveBatch(insertList);
        }
    }

    private List<EmsModuleConfig> strategyToModuleConfigList(StrategyControlRequestVO requestVO, Map<String, EmsDevice> deviceMap) {
        List<EmsModuleConfig> result = Lists.newArrayList();
        EmsDevice device = deviceMap.get(requestVO.getDeviceCode());
        if (!StringUtils.isEmpty(requestVO.getYk()) && requestVO.getYkDitType() != null) {
            //投入/退出遥控
            EmsModuleConfig yk = EmsModuleConfig.builder()
                    .category(ModulePositionEnum.fromCode(requestVO.getModule()).getCategoryEnum().getCode())
                    .module(requestVO.getModule()).deviceCode(requestVO.getDeviceCode()).sortNum(1)
                    .initDeviceCode(device.getInitDeviceCode())
                    .pidName(requestVO.getYkName()).gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis())
                    .pid(device.getInitDeviceCode() + SysConstant.SPOT + requestVO.getYk()).ditType(requestVO.getYkDitType())
                    .groupId(requestVO.getGroupId())
                    .build();
            result.add(yk);
        }
        //动作遥信
        if (!StringUtils.isEmpty(requestVO.getActionYx()) && requestVO.getActionYxDitType() != null) {
            EmsModuleConfig actionYx = EmsModuleConfig.builder()
                    .category(ModulePositionEnum.fromCode(requestVO.getModule()).getCategoryEnum().getCode())
                    .module(requestVO.getModule()).deviceCode(requestVO.getDeviceCode()).sortNum(2)
                    .initDeviceCode(device.getInitDeviceCode())
                    .pidName(requestVO.getActionYxName()).gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis())
                    .pid(device.getInitDeviceCode() + SysConstant.SPOT + requestVO.getActionYx()).ditType(requestVO.getActionYxDitType())
                    .groupId(requestVO.getGroupId())
                    .build();
            result.add(actionYx);
        }
        //投入/退出遥信
        if (!StringUtils.isEmpty(requestVO.getYx()) && requestVO.getYxDitType() != null) {
            EmsModuleConfig yx = EmsModuleConfig.builder()
                    .category(ModulePositionEnum.fromCode(requestVO.getModule()).getCategoryEnum().getCode())
                    .module(requestVO.getModule()).deviceCode(requestVO.getDeviceCode()).sortNum(3)
                    .initDeviceCode(device.getInitDeviceCode())
                    .pidName(requestVO.getYxName()).gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis())
                    .pid(device.getInitDeviceCode() + SysConstant.SPOT + requestVO.getYx()).ditType(requestVO.getYxDitType())
                    .groupId(requestVO.getGroupId())
                    .build();
            result.add(yx);
        }
        return result;
    }

    public List<StrategyControlVO> getStrategyControl() {
        List<EmsStrategyConfig> emsStrategyConfigs = emsStrategyConfigDAO.selectByCondition(DisplayType.DISPLAY.getCode(), null);
        if (CollectionUtils.isEmpty(emsStrategyConfigs)) {
            return Lists.newArrayList();
        }
        return this.getStrategyControlVOS(emsStrategyConfigs,null);
    }

    private List<StrategyControlVO> getStrategyControlVOS(List<EmsStrategyConfig> emsStrategyConfigs,Integer groupId) {
         //获取对应的类别枚举有哪些
        List<CategoryEnum> categoryEnumList = CategoryEnum.fromNames(emsStrategyConfigs.stream().map(d->d.getStrategyId()).collect(Collectors.toList()));
        /** 获取strategyConfigMap与之对应的module(位置)有哪些 */
        List<ModulePositionEnum> modulePositionEnumList = ModulePositionEnum.fromCategoryEnums(categoryEnumList);
        modulePositionEnumList = modulePositionEnumList.stream().filter(d->d.getControlType()).collect(Collectors.toList());
        List<Integer> moduleList = modulePositionEnumList.stream().map(d -> d.getCode()).collect(Collectors.toList());
        //modulePositionEnumList按照CategoryEnum分组，key:CategoryEnum
        Map<CategoryEnum,List<ModulePositionEnum>> modulePositionMap = modulePositionEnumList.stream().collect(Collectors.groupingBy(d->d.getCategoryEnum()));
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModuleList(moduleList);
        //遥信实时数据map,key:pid,value:值
        Map<String, String> yxValueMap = Maps.newHashMap();
        //设备与设备名称对应map,key:deviceCode,value:deviceName
        Map<String, String> deviceMap = Maps.newHashMap();
        //遥控下发信息Map，key：deviceCode(iot设备编号) + . + serviceCode
        Map<String, IotSyncMsgDTO> ykMap = Maps.newHashMap();
        //EmsModuleConfig分组，第一个key：module,第二个key: groupId, value:List<EmsModuleConfig>
        Map<Integer,Map<Integer,List<EmsModuleConfig>>> moduleGroupConfigMap = Maps.newHashMap();
        emsModuleConfigs.stream().collect(Collectors.groupingBy(EmsModuleConfig::getModule)).forEach((module,list)->{
            moduleGroupConfigMap.put(module,list.stream().collect(Collectors.groupingBy(EmsModuleConfig::getGroupId)));
        });
        //获取EMS设备编号
        List<String> deviceCodeList = emsModuleConfigs.stream().map(EmsModuleConfig::getDeviceCode).collect(Collectors.toList());
        //设备与设备名称对应map,key:deviceCode,value:deviceName
        deviceMap = emsDeviceDAO.selectByDeviceCodes(deviceCodeList).stream()
                .collect(Collectors.toMap(EmsDevice::getDeviceCode, EmsDevice::getDeviceName));
        //获取遥信实时数据
        List<QueryDataVO> yxQueryDataVO = emsModuleConfigs.stream().filter(d -> d.getDitType().equals(DitTypeEnum.YX.getCode())).distinct().map(d ->
                QueryDataVO.builder().pid(d.getPid()).deviceCode(d.getDeviceCode()).initDeviceCode(d.getInitDeviceCode())
                        .dit(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, "")).build()
        ).collect(Collectors.toList());
        List<FlashDataVO> flashData = queryFlashDataCommonService.getFlashData(yxQueryDataVO);
        if (CollectionUtils.isNotEmpty(flashData)) {
            yxValueMap.putAll(flashData.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal)));
        }
        //获取遥控下发信息
        List<IotSyncMsgDTO> ykList = this.getYkSyncMsgList("yk", emsModuleConfigs
                .stream().filter(d->d.getDitType().equals(DitTypeEnum.YK.getCode())).collect(Collectors.toList()));
        if (CollectionUtils.isNotEmpty(ykList)) {
            ykMap.putAll(ykList.stream().collect(Collectors.toMap(d -> d.getDeviceCode() + SysConstant.SPOT + d.getServiceCode(), d -> d)));
        }
        return this.createStrategyControlDataList(emsStrategyConfigs,modulePositionMap,emsModuleConfigs,yxValueMap,ykMap,deviceMap,groupId);
    }

    /**
     * 构建策略控制的数据
     * @param emsStrategyConfigs：调度控制的配置VO集合
     * @param modulePositionMap：调度控制位置信息map
     * @param emsModuleConfigs: 模块点号配置VO集合
     * @param yxValueMap：遥信实时数据map,key:pid,value:值
     * @param ykMap：遥控下发信息Map，key：initDeviceCode(iot设备编号) + . + serviceCode
     * @param deviceMap：设备与设备名称对应map key:deviceCode(EMS设备编号),value:deviceName
     * @return
     */
    private List<StrategyControlVO> createStrategyControlDataList(List<EmsStrategyConfig> emsStrategyConfigs,
                                                                  Map<CategoryEnum,List<ModulePositionEnum>> modulePositionMap,
                                                                  List<EmsModuleConfig> emsModuleConfigs,
                                                                  Map<String, String> yxValueMap,
                                                                  Map<String, IotSyncMsgDTO> ykMap,
                                                                  Map<String, String> deviceMap,
                                                                  Integer groupId){
        List<StrategyControlVO> result = Lists.newArrayList();
        //每一个策略有几个分组,key:strategyId,value:groupNum
        Map<String,Integer> strategyConfigMap = emsStrategyConfigs.stream().collect(Collectors.toMap(d->d.getStrategyId(),d->d.getGroupNum()));
        //EmsModuleConfig分组，第一个key：module,第二个key: groupId, value:List<EmsModuleConfig>
        Map<Integer,Map<Integer,List<EmsModuleConfig>>> moduleGroupConfigMap = Maps.newHashMap();
        emsModuleConfigs.stream().collect(Collectors.groupingBy(EmsModuleConfig::getModule)).forEach((module,list)->{
            moduleGroupConfigMap.put(module,list.stream().collect(Collectors.groupingBy(EmsModuleConfig::getGroupId)));
        });
        emsStrategyConfigs.stream().forEach(strategyConfig ->{
            CategoryEnum categoryEnum = CategoryEnum.fromName(strategyConfig.getStrategyId());
            //获取该策略对应的ModulePositionEnum有哪些
            List<ModulePositionEnum> positionEnums = CollectionUtils.isEmpty(modulePositionMap.get(categoryEnum))?
                    Lists.newArrayList():modulePositionMap.get(categoryEnum);
            //该策略下的分组的数据
            List<StrategyControlGroupVO> groupData = Lists.newArrayList();
            for (int i=1; i <= strategyConfigMap.get(strategyConfig.getStrategyId()); i++){
                List<StrategyControlGroupModuleVO> groupModuleVOS = Lists.newArrayList();
                for (ModulePositionEnum moduleEnum : positionEnums){
                    //获取某个module,某个groupId下的数据
                    List<EmsModuleConfig> moduleConfigs = MapUtils.isEmpty(moduleGroupConfigMap.get(moduleEnum.getCode()))?
                            Lists.newArrayList():CollectionUtils.isEmpty(moduleGroupConfigMap.get(moduleEnum.getCode()).get(i))?
                            Lists.newArrayList():moduleGroupConfigMap.get(moduleEnum.getCode()).get(i);
                    //组装某个module,某个groupId下的数据
                    StrategyControlGroupModuleVO groupModuleVO = this.moduleConfigListToStrategyControlVO(moduleConfigs, yxValueMap, ykMap,deviceMap);
                    groupModuleVO.setGroupId(i);
                    groupModuleVO.setModule(moduleEnum.getCode());
                    groupModuleVO.setModuleName(moduleEnum.getDesc());
                    groupModuleVO.setStrategyId(strategyConfig.getStrategyId());
                    groupModuleVO.setStrategyName(strategyConfig.getStrategyName());
                    //投入遥控、遥信值相同时将sendStatus设置为null
                    if (!StringUtils.isEmpty(groupModuleVO.getYkValue()) && !StringUtils.isEmpty(groupModuleVO.getYxValue())) {
                        if (groupModuleVO.getYkValue().equals(groupModuleVO.getYxValue())){
                            groupModuleVO.setSendStatus(null);
                        }
                    }
                    groupModuleVOS.add(groupModuleVO);
                }
                if (groupId!=null){
                    if (groupId.equals(i)){
                        groupData.add(StrategyControlGroupVO.builder()
                            .groupId(i)
                            .groupModuleData(groupModuleVOS)
                            .build());
                    }
                }else{
                    groupData.add(StrategyControlGroupVO.builder()
                            .groupId(i)
                            .groupModuleData(groupModuleVOS)
                            .build());
                }

            }
            result.add(StrategyControlVO.builder()
                    .strategyId(strategyConfig.getStrategyId())
                    .strategyName(strategyConfig.getStrategyName())
                    .groupData(groupData)
                    .build());
        });
        return result;
    }

    private StrategyControlGroupModuleVO moduleConfigListToStrategyControlVO(List<EmsModuleConfig> moduleConfigList
            , Map<String, String> yxValueMap, Map<String, IotSyncMsgDTO> ykMap, Map<String, String> deviceMap) {
        StrategyControlGroupModuleVO result = StrategyControlGroupModuleVO.builder().build();
        moduleConfigList.stream().sorted(Comparator.comparing(EmsModuleConfig::getSortNum)).forEach(d -> {
            result.setDeviceCode(d.getDeviceCode())
                    .setInitDeviceCode(d.getInitDeviceCode())
                    .setGroupId(d.getGroupId())
                    .setDeviceName(deviceMap.get(d.getDeviceCode()));
            if (d.getSortNum().equals(1)) {
                result.setYk(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, ""))
                        .setYkName(d.getPidName()).setYkDitType(d.getDitType())
                        .setYkDitTypeName(DitTypeEnum.getDescFromCode(d.getDitType()))
                        .setYkPid(d.getPid());
                if (ykMap.containsKey(d.getPid())) {
                    IotSyncMsgDTO iotSyncMsgDTO = ykMap.get(d.getPid());
                    result.setYkValue(iotSyncMsgDTO.getValue())
                            .setSendStatus(iotSyncMsgDTO.getSendStatus())
                            .setSendStatusName(iotSyncMsgDTO.getSendStatusName());
                }
            }
            if (d.getSortNum().equals(2)) {
                result.setActionYx(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, ""))
                        .setActionYxName(d.getPidName()).setActionYxDitType(d.getDitType())
                        .setActionYxDitTypeName(DitTypeEnum.getDescFromCode(d.getDitType()))
                        .setActionYxPid(d.getPid());
                if (yxValueMap.containsKey(d.getPid())) {
                    result.setActionYxValue(yxValueMap.get(d.getPid()));
                }
            }
            if (d.getSortNum().equals(3)) {
                result.setYx(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, ""))
                        .setYxName(d.getPidName()).setYxDitType(d.getDitType())
                        .setYxDitTypeName(DitTypeEnum.getDescFromCode(d.getDitType()))
                        .setYxPid(d.getPid());
                if (yxValueMap.containsKey(d.getPid())) {
                    result.setYxValue(yxValueMap.get(d.getPid()));
                }
            }
        });
        return result;
    }

    private List<IotSyncMsgDTO> getYkSyncMsgList(String serviceId, List<EmsModuleConfig> emsModuleConfigs) {
        List<IotSyncMsgDTO> result = Lists.newArrayList();
        if (CollectionUtils.isEmpty(emsModuleConfigs)) {
            return Lists.newArrayList();
        }
        List<String> deviceCodeList = emsModuleConfigs.stream().map(EmsModuleConfig::getInitDeviceCode).collect(Collectors.toList());
        List<String> ditList = emsModuleConfigs.stream()
                .map(d -> d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, ""))
                .collect(Collectors.toList());
        //获取最新一条设定数据
        List<IotEdgePlatformSyncMsg> iotEdgePlatformSyncMsgs = iotMqttSyncMsgDAO.selectLastListByCondition(serviceId, deviceCodeList, ditList);
        if (CollectionUtils.isEmpty(iotEdgePlatformSyncMsgs)) {
            return result;
        }
        List<Integer> msgPidList = iotEdgePlatformSyncMsgs.stream().map(IotEdgePlatformSyncMsg::getPid).collect(Collectors.toList());
        //获取msg对应的来自非设备端的detail最新数据
        List<IotEdgePlatformSyncMsgDetail> iotEdgePlatformSyncMsgDetails = iotMqttSyncMsgDetailDAO
                .selectLastListByParentPid(msgPidList, Arrays.stream(EdgeSendSourceMsgType.values())
                        .filter(d -> d != EdgeSendSourceMsgType.FROM_DEVICE)
                        .map(EdgeSendSourceMsgType::getCode).collect(Collectors.toList()));
        //解析detail数据得到设定值
        Map<Integer, String> pidValueMap = new HashMap<>();
        iotEdgePlatformSyncMsgDetails.stream().forEach(d -> {
            SvcPushPayload servicePayload = JSON.parseObject(d.getPayload(), SvcPushPayload.class);
            if (servicePayload != null && servicePayload.getParams() != null) {
                Map<String, Object> value = servicePayload.getParams().getValue();
                pidValueMap.put(d.getParentPid(), value.get("value").toString());
            }
        });
        iotEdgePlatformSyncMsgs.stream().forEach(d -> {
            IotSyncMsgDTO build = IotSyncMsgDTO.builder()
                    .deviceCode(d.getDeviceCode()).productKey(d.getProductKey())
                    .sendStatus(d.getSendStatus()).serviceId(d.getServiceId())
                    .serviceCode(d.getServiceCode()).msgType(d.getMsgType())
                    .msgTypeName(EdgeSendSourceMsgType.fromCode(d.getMsgType()).getDesc())
                    .sendStatusName(IotMsgStatus.fromCode(d.getSendStatus()).getDesc()).build();
            if (pidValueMap.containsKey(d.getPid())) {
                build.setValue(pidValueMap.get(d.getPid()));
            }
            result.add(build);
        });
        return result;
    }

    public StrategyControlVO control(String strategyId,Integer groupId) {
        EmsStrategyConfig emsStrategyConfig = emsStrategyConfigDAO.selectByStrategyId(strategyId);
        Assert.notNull(emsStrategyConfig, "策略不存在");
        if (emsStrategyConfig.getDisplay().equals(DisplayType.NOT_DISPLAY)) {
            return null;
        }
        List<StrategyControlVO> strategyControlVOS = this.getStrategyControlVOS(Lists.newArrayList(emsStrategyConfig),groupId);
        if (CollectionUtils.isEmpty(strategyControlVOS)){
            return null;
        }
        return strategyControlVOS.get(0);
    }

    /**
     *
     * @param module: 模块(如AGC控制,AGC统计数据等)
     * @param groupId: 分组id
     * @param value 1标识投入，0表示退出，同事默认yx值为1时是动作中，遥控为1时是投入
     */
    @Transactional(rollbackFor = Exception.class)
    public void activeOrQuit(Integer module, Integer groupId, Integer value) {
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModuleAndGroupId(module,groupId);
        Assert.isTrue(CollectionUtils.isNotEmpty(emsModuleConfigs), "请先配置点号!");
        List<EmsModuleConfig> ykConfig = emsModuleConfigs.stream()
                .filter(d -> d.getDitType().equals(DitTypeEnum.YK.getCode())).collect(Collectors.toList());
        Assert.isTrue(CollectionUtils.isNotEmpty(ykConfig) && ykConfig.size() == 1, "遥控点号有且仅有一个，请检查配置!");
        EmsModuleConfig yk = ykConfig.get(0);

        //获取遥控下发信息
        List<IotSyncMsgDTO> ykList = this.getYkSyncMsgList("yk", emsModuleConfigs
                .stream().filter(d->d.getDitType().equals(DitTypeEnum.YK.getCode())).collect(Collectors.toList()));
        Map<String, IotSyncMsgDTO> ykMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(ykList)) {
            ykMap.putAll(ykList.stream().collect(Collectors.toMap(d -> d.getDeviceCode() + SysConstant.SPOT + d.getServiceCode(), d -> d)));
        }
        IotSyncMsgDTO iotSyncMsgDTO = ykMap.get(yk.getPid());
        //检查是否可以下发
        Assert.isTrue(iotSyncMsgDTO == null ||
                IotMsgStatus.getFinalStatus().stream().anyMatch(d -> d.getCode().equals(iotSyncMsgDTO.getSendStatus())), "下发中，请稍后重试!");
        //检查设备是否挂牌检修(检修则不下发)
        Integer listingType = extIotNodeDAO.selectByNodeId(yk.getDeviceCode()).getListingType();
        Assert.isTrue(!ListingTypeEnum.OVERHAUL.getCode().equals(listingType),"设备检修中");
        MsgResult<Integer> msgResult = iFeignPowerNodeConsoleClient
                .yk(NetUtils.getClientIp(),null,yk.getInitDeviceCode(), yk.getPid().replace(yk.getInitDeviceCode() + SysConstant.SPOT, ""), value,false);
        if (StatusType.OK.getCode() != msgResult.getStatus()) {
            throw new CommonRuntimeException(StatusType.FAIL, FaultDesc.FAILURE_ISSUE.getDesc());
        }
    }

    public RunMonitorVO runMonitor() {
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO
                .selectListByModuleList(Lists.newArrayList(ModulePositionEnum.RUN_MONITOR.getCode()));
        Assert.isTrue(CollectionUtils.isNotEmpty(emsModuleConfigs),"实时监控未配置！请先配置！");
        List<String> deviceCodeList = emsModuleConfigs.stream().map(EmsModuleConfig::getDeviceCode).collect(Collectors.toList());
        Map<String, String> deviceMap = emsDeviceDAO.selectByDeviceCodes(deviceCodeList).stream()
                .collect(Collectors.toMap(EmsDevice::getDeviceCode, EmsDevice::getDeviceName));

        //获取遥信实时数据
        List<QueryDataVO> ycQueryDataVO = emsModuleConfigs.stream().filter(d -> d.getDitType().equals(DitTypeEnum.CAL_YC.getCode())).distinct().map(d ->
                QueryDataVO.builder().pid(d.getPid()).deviceCode(d.getDeviceCode()).initDeviceCode(d.getInitDeviceCode())
                        .dit(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT, "")).build()
        ).collect(Collectors.toList());
        List<FlashDataVO> flashData = queryCalDataCommonService.getCalData(ycQueryDataVO);
        Map<String, String> calYcValueMap = flashData.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
        RunMonitorVO result = RunMonitorVO.builder().build();
        EmsModuleConfig emsModuleConfig = emsModuleConfigs.get(0);
        result.setDeviceCode(emsModuleConfig.getDeviceCode())
                .setDeviceName(deviceMap.get(emsModuleConfig.getDeviceCode()))
                .setInitDeviceCode(emsModuleConfig.getInitDeviceCode());
        emsModuleConfigs.stream().forEach(d->{
            if (d.getSortNum().equals(1)){
                result.setSocUnit(d.getUnit())
                        .setSocValue(calYcValueMap.get(d.getPid()))
                        .setSocPid(d.getPid())
                        .setSocName(d.getPidName());
            }else if (d.getSortNum().equals(2)){
                result.setTodayChargeUnit(d.getUnit())
                        .setTodayChargeValue(calYcValueMap.get(d.getPid()))
                        .setTodayChargePid(d.getPid())
                        .setTodayChargeName(d.getPidName());
            }else if (d.getSortNum().equals(3)){
                result.setTodayDisChargeUnit(d.getUnit())
                        .setTodayDisChargeValue(calYcValueMap.get(d.getPid()))
                        .setTodayDisChargePid(d.getPid())
                        .setTodayDisChargeName(d.getPidName());
            }else if (d.getSortNum().equals(4)){
                result.setTodayConsumeUnit(d.getUnit())
                        .setTodayConsumeValue(calYcValueMap.get(d.getPid()))
                        .setTodayConsumePid(d.getPid())
                        .setTodayConsumeName(d.getPidName());
            }
        });
        return result;
    }

    public List<HisChartDataVO> getSevenDayHisDataByModule(Integer module, Boolean isAsc) {
        List<HisChartDataVO> resultList = Lists.newArrayList();
        //获取该位置所配置的点号
        List<EmsModuleConfig> emsModuleConfigs = emsModuleConfigDAO.selectListByModule(module);
        List<String> ycPids = emsModuleConfigs.stream()
                .filter(e -> e.getDitType().equals(DitTypeEnum.YC.getCode())
                        || e.getDitType().equals(DitTypeEnum.CAL_YC.getCode()))
                .map(EmsModuleConfig::getPid).collect(Collectors.toList());
        List<String> yxPids = emsModuleConfigs.stream()
                .filter(e -> e.getDitType().equals(DitTypeEnum.YX.getCode())
                        || e.getDitType().equals(DitTypeEnum.CAL_YX.getCode()))
                .map(EmsModuleConfig::getPid).collect(Collectors.toList());
        //不同类别分别查询数据
        Map<String, List<AnalogData>> ycDataMap = Maps.newHashMap();
        Map<String, List<StatusData>> yxDataMap = Maps.newHashMap();
        Long endTime = System.currentTimeMillis();
        long todayStartTime = TimeUtil.getDayStartTime(new Date(endTime));
        Long startTime = TimeUtil.getDayStartTime(new Date(endTime), -7);
        if (CollectionUtils.isNotEmpty(ycPids)) {
            ycDataMap = analogDataDAO.selectByPidsAndTime(ycPids, isAsc, startTime, endTime)
                    .stream().collect(Collectors.groupingBy(d -> d.getPid(), LinkedHashMap::new, Collectors.toList()));
        }
        if (CollectionUtils.isNotEmpty(yxPids)) {
            yxDataMap = statusDataDAO.selectByPidsAndTime(yxPids, isAsc, startTime, endTime)
                    .stream().collect(Collectors.groupingBy(d -> d.getPid(), LinkedHashMap::new, Collectors.toList()));
        }
        for (EmsModuleConfig config : emsModuleConfigs) {
            List<ChartDataVO> chartDataVOList = Lists.newArrayList();
            if (config.getDitType().equals(DitTypeEnum.YC.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YC.getCode())) {
                //遥测或者计算遥测
                List<AnalogData> analogDatas = ycDataMap.get(config.getPid());
                if (CollectionUtils.isNotEmpty(analogDatas)) {
                    Long dayStartTime = todayStartTime;
                    Long dayEndTime = TimeUtil.getDayEndTime(new Date(dayStartTime));
                    while (dayStartTime >= startTime) {
                        Long start = dayStartTime;
                        Long end = dayEndTime;
                        List<AnalogData> analogDataList = analogDatas.stream().filter(d -> d.getT() >= start && d.getT() <= end)
                                .sorted(Comparator.comparing(AnalogData::getT).reversed()).collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(analogDataList)){
                            AnalogData analogData = analogDataList.get(0);
                            chartDataVOList.add(ChartDataVO.builder().time(analogData.getT()).val(analogData.getV()).build());
                        }
                        dayStartTime = TimeUtil.getDayStartTime(new Date(dayStartTime), -1);
                        dayEndTime = TimeUtil.getDayEndTime(new Date(dayStartTime));
                    }
                }
            } else if (config.getDitType().equals(DitTypeEnum.YX.getCode()) || config.getDitType().equals(DitTypeEnum.CAL_YX.getCode())) {
                //遥信或者计算遥信
                List<StatusData> statusDatas = yxDataMap.get(config.getPid());
                if (CollectionUtils.isNotEmpty(statusDatas)) {
                    Long dayStartTime = todayStartTime;
                    Long dayEndTime = TimeUtil.getDayEndTime(new Date(dayStartTime));
                    while (dayStartTime >= startTime) {
                        Long start = dayStartTime;
                        Long end = dayEndTime;
                        List<StatusData> statusDataList = statusDatas.stream().filter(d -> d.getT() >= start && d.getT() <= end)
                                .sorted(Comparator.comparing(StatusData::getT).reversed()).collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(statusDataList)){
                            StatusData statusData = statusDataList.get(0);
                            chartDataVOList.add(ChartDataVO.builder().time(statusData.getT()).val(statusData.getV()).build());
                        }
                        dayStartTime = TimeUtil.getDayStartTime(new Date(dayStartTime), -1);
                        dayEndTime = TimeUtil.getDayEndTime(new Date(dayStartTime));
                    }
                }
            }
            chartDataVOList = chartDataVOList.stream().sorted(isAsc ? Comparator.comparing(ChartDataVO::getTime)
                    : Comparator.comparing(ChartDataVO::getTime).reversed()).collect(Collectors.toList());
            HisChartDataVO hisChartDataVO = HisChartDataVO.builder().pidAliasName(config.getPidAliasName())
                    .deviceCode(config.getDeviceCode()).ditType(config.getDitType()).pid(config.getPid()).datas(chartDataVOList).build();
            resultList.add(hisChartDataVO);
        }
        return resultList;
    }

    public List<DeviceMonitorVO> getDeviceMonitor(String stationId, Integer showType) {
        List<DeviceMonitorVO> result = Lists.newArrayList();
        List<EmsDeviceMonitorConfig> configList = emsDeviceMonitorConfigDAO.getListByCondition(stationId, null, showType);
        Assert.isTrue(CollectionUtils.isNotEmpty(configList), "请先配置监控点号！");
        List<EmsDevice> deviceList = emsDeviceDAO.getListByStationIdAndEquipmentIdAndDeviceTypes(stationId,null,
                configList.stream().map(EmsDeviceMonitorConfig::getDeviceType).collect(Collectors.toList()));
        Assert.isTrue(CollectionUtils.isNotEmpty(deviceList),  "请检查配置是否正确");
        Map<String, List<EmsDevice>> deviceMap = deviceList.stream().collect(Collectors.groupingBy(EmsDevice::getEnergyEquipmentId));
        //储能装置信息
        List<EmsEnergyEquipment> equipments = emsEnergyEquipmentDAO.selectByStationIds(Lists.newArrayList(stationId));
        Assert.isTrue(CollectionUtils.isNotEmpty(equipments),"不存在储能装置");
        Map<String, String> equipmentMap = equipments.stream().collect(Collectors
                .toMap(EmsEnergyEquipment::getEnergyEquipmentId, EmsEnergyEquipment::getEnergyEquipmentName));

        //计算点号
        List<EmsDeviceMonitorConfig> calConfigList = configList.stream().filter(d ->
                !StringUtils.isEmpty(d.getCalTag())).collect(Collectors.toList());
        List<QueryDataVO> calQueryDataVOList = Lists.newArrayList();
        List<QueryDataVO> queryDataVOList = Lists.newArrayList();
        //<tag,<nodeId,computeCode>>
        Map<String, Map<String, String>> tagCalMap = Maps.newHashMap();
        //<computeCode,tag>
        Map<String, String> calTagMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(calConfigList)){
            //获取tagCalMap和calTagMap数据
            List<ExtIotViceCalculation> calList = extIotViceCalculationDAO.getListByVal2TagList(calConfigList.stream()
                    .map(EmsDeviceMonitorConfig::getCalTag).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(calList)){
                Map<String, List<ExtIotViceCalculation>> calMap = calList.stream().collect(Collectors.groupingBy(ExtIotViceCalculation::getVal2));
                calMap.forEach((key,value)->{
                    Map<String, String> nodeMap = value.stream().collect(Collectors
                            .toMap(ExtIotViceCalculation::getNodeId, ExtIotViceCalculation::getComputeCode));
                    tagCalMap.put(key,nodeMap);
                });
                calTagMap.putAll(calList.stream().collect(Collectors.toMap(ExtIotViceCalculation::getComputeCode,ExtIotViceCalculation::getVal2)));
            }
        }
        List<String> productKeyList = deviceList.stream().map(EmsDevice::getProductKey).collect(Collectors.toList());
        List<IotProductEventScript> eventScriptList = productEventScriptDAO.selectListByProductKeyList(productKeyList);
        //<productkey.dit.emergency,CrossLine>
        Map<String, CrossLine> eventMap = eventScriptList.stream().collect(Collectors
                .toMap(d -> d.getProductKey() + SysConstant.SPOT + d.getSourceCode() + SysConstant.SPOT + d.getEmergency()
                        , s->{
                            String script = s.getScript();
                            String[] scripts = script.split("&&");
                            String min = scripts[0].replace("num","").replace("<","").replace(">","").trim();
                            String max = scripts[1].replace("num","").replace("<","").replace(">","").trim();
                            CrossLine crossLine = CrossLine.builder().min("null".equals(max) ? null : Double.valueOf(max))
                                    .max("null".equals(min) ? null : Double.valueOf(min)).build();
                            return crossLine;
                        }, (d1, d2) -> d2));

        equipments.stream().forEach(d->{
            //基本信息
            DeviceMonitorVO monitorVO = DeviceMonitorVO.builder().equipmentId(d.getEnergyEquipmentId())
                    .equipmentName(d.getEnergyEquipmentName()).build();
            List<EmsDevice> emsDeviceList = deviceMap.get(d.getEnergyEquipmentId());
            if (CollectionUtils.isEmpty(emsDeviceList)){
                //储能装置无对应设备
                result.add(monitorVO);
                return;
            }
            List<DeviceMonitorDataVO> dataList = Lists.newArrayList();
            //允许每个储能装置配多个设备，此时全部返回给前端
            emsDeviceList.stream().forEach(device->{

                configList.stream().forEach(config->{
                    String dit = null;
                    if (DitTypeEnum.YC.getCode().equals(config.getDitType())||DitTypeEnum.YX.getCode().equals(config.getDitType())){
                        dit = "def".equals(device.getModuleCode())?config.getDit():device.getModuleCode()+SysConstant.SPOT+config.getDit();
                        //实测数据
                        DeviceMonitorDataVO data = DeviceMonitorDataVO.builder().pid(device.getInitDeviceCode() + SysConstant.SPOT + dit)
                                .unit(config.getUnit()).ditType(config.getDitType()).name(config.getName())
                                .deviceCode(device.getDeviceCode()).deviceName(device.getDeviceName())
                                .ditTypeName(DitTypeEnum.getDescFromCode(config.getDitType())).sortNum(config.getSortNum()).build();
                        String middleKey = device.getProductKey() + SysConstant.SPOT + dit + SysConstant.SPOT + EventEmergency.MIDDLE.getCode();
                        if (eventMap.containsKey(middleKey)){
                            //越线
                            data.setCrossLine(eventMap.get(middleKey));
                        }
                        String severe = device.getProductKey() + SysConstant.SPOT + dit + SysConstant.SPOT + EventEmergency.SEVERE.getCode();
                        if (eventMap.containsKey(severe)){
                            //严重越线
                            data.setCrossLine(eventMap.get(severe));
                        }
                        dataList.add(data);
                        QueryDataVO queryDataVO = QueryDataVO.builder().dit(dit)
                                .initDeviceCode(device.getInitDeviceCode()).deviceCode(device.getDeviceCode())
                                .pid(device.getInitDeviceCode() + SysConstant.SPOT + dit).build();
                        queryDataVOList.add(queryDataVO);
                    }else {
                        //计算数据
                        if (!tagCalMap.containsKey(config.getCalTag())){
                            return;
                        }
                        //<nodeId,computeCode>----emdDevice中的deviceCode=nodeId
                        Map<String, String> nodeMap = tagCalMap.get(config.getCalTag());
                        String computeCode = nodeMap.get(device.getDeviceCode());
                        if (StringUtils.isEmpty(computeCode)){
                            return;
                        }
                        DeviceMonitorDataVO data = DeviceMonitorDataVO.builder().pid(computeCode).unit(config.getUnit())
                                .ditType(config.getDitType()).name(config.getName()).sortNum(config.getSortNum())
                                .deviceCode(device.getDeviceCode()).deviceName(device.getDeviceName())
                                .ditTypeName(DitTypeEnum.getDescFromCode(config.getDitType())).build();
                        dataList.add(data);
                        dit = computeCode.replace(device.getInitDeviceCode() + SysConstant.SPOT, "");
                        QueryDataVO queryDataVO = QueryDataVO.builder().dit(dit).initDeviceCode(device.getInitDeviceCode())
                                .deviceCode(device.getDeviceCode()).pid(computeCode).build();
                        calQueryDataVOList.add(queryDataVO);
                    }
                    monitorVO.setData(dataList);
                });
            });
            result.add(monitorVO);
        });

        List<FlashDataVO> runDataList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(calQueryDataVOList)){
            runDataList.addAll(queryCalDataCommonService.getCalData(calQueryDataVOList));
        }
        if (CollectionUtils.isNotEmpty(queryDataVOList)){
            runDataList.addAll(queryFlashDataCommonService.getFlashData(queryDataVOList));
        }
        Map<String, String> dataMap = runDataList.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
        valueInfos(result,dataMap,calTagMap);
        return result;
    }

    private void valueInfos(List<DeviceMonitorVO> result,Map<String, String> dataMap,Map<String,String> calTagMap){
        result.stream().forEach(monitor->{
            List<DeviceMonitorDataVO> dataList = monitor.getData();
            dataList.stream().forEach(data->{
                String value = dataMap.get(data.getPid());
                data.setValue(value);
                if (StringUtils.isEmpty(value)){
                    return;
                }
                if (DitTypeEnum.YX.getCode().equals(data.getDitType())){
                    if ("1".equals(value)){
                        data.setStatusName("启动");
                    }else {
                        data.setStatusName("停机");
                    }
                }
                if (calTagMap.containsKey(data.getPid())){
                    String tag = calTagMap.get(data.getPid());
                    if (CalTagEnums.BMS_FAULT_ALARM.getCode().equals(tag)
                    ||CalTagEnums.PCS_FAULT_ALARM.getCode().equals(tag)){
                        data.setStatusName(AlarmOrFaultState.getDescFromCode(Integer.parseInt(value)));
                    }
                    if (CalTagEnums.PCS_RUN.getCode().equals(tag)){
                        data.setStatusName(PcsOrPcuRunStatus.fromCode(Integer.parseInt(value)).getDesc());
                    }
                }
            });
        });
    }

    private void createConstantConfigQueryData(Map<String, EmsDevice> deviceMap,List<EmsConstantConfig> constantConfigs,
                                               List<QueryDataVO> queryList,List<QueryDataVO> calQueryList){
        constantConfigs.stream().forEach(d->{
            EmsDevice emsDevice = deviceMap.get(d.getDeviceCode());
            //某些不存在的设备直接跳过
            if(emsDevice == null){
                return;
            }
            if(d.getFeedBackDit() != null){
                QueryDataVO queryDataVO = QueryDataVO.builder()
                        .deviceCode(d.getDeviceCode())
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getFeedBackDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(d.getFeedBackDit())
                        .build();
                if(DitTypeEnum.isFlashData(d.getFeedBackDitType())){
                    queryList.add(queryDataVO);
                }else if(DitTypeEnum.isCalData(d.getFeedBackDitType())){
                    calQueryList.add(queryDataVO);
                }
            }
            if(d.getActualDit() != null){
                QueryDataVO queryDataVO = QueryDataVO.builder()
                        .deviceCode(d.getDeviceCode())
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getActualDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(d.getFeedBackDit())
                        .build();
                if(DitTypeEnum.isFlashData(d.getActualDitType())){
                    queryList.add(queryDataVO);
                }else if(DitTypeEnum.isCalData(d.getActualDitType())){
                    calQueryList.add(queryDataVO);
                }
            }
        });
    }
}
